﻿using System;
using System.Collections;

namespace EaWebService
{

    /// <summary>
    /// Class for population unit - integer representation
    /// </summary>
    class UnitInt : IMutation
    {
        private int[] genCode;
        public int[] GenCode
        {
            get { return genCode; }
            set { genCode = value; }
        }
        private int length;
        public int Length
        {
            get { return length; }
            set { length = value; }
        }
        private double fitnessValue;
        public double FitnessValue
        {
            get { return fitnessValue; }
            set { fitnessValue = value; }
        }

        public UnitInt(int length, int[] genCode, double fitnessValue = 0)
        {
            this.length = length;
            this.genCode = genCode;
            this.fitnessValue = fitnessValue;
        }

        public UnitInt()
        {
            this.length = 0;
            this.genCode = new int[0];
            this.fitnessValue = 0;
        }




        //IMutation interface
        public void MutationRandom()
        {
            //Number of gene mutations
            Random rand = new Random();
            int count = 0;
            while (count == 0)
            {
                count = rand.Next(genCode.Length);
            }

            //Mutating genes
            for (int i = 0; i < count; i++)
            {
                int pos = rand.Next(genCode.Length);
                genCode[pos] = (genCode[pos] * count) % 4 + 1;
            }
        }

        public void MutationExchange()
        {
            //Two genes change places
            Random rand = new Random();
            int pos1 = rand.Next(genCode.Length);
            int pos2 = pos1;
            while (pos2 == pos1)
            {
                pos2 = rand.Next(genCode.Length);
            }

            int pom = genCode[pos1];
            genCode[pos1] = genCode[pos2];
            genCode[pos2] = pom;
        }

        public void MutationDisplacement()
        {
            //Copy seqence of genes to annother location.
            Random rand = new Random();
            int pos1 = rand.Next(genCode.Length);
            while (pos1 == 0)
            {
                pos1 = rand.Next(genCode.Length);
            }
            int pos2 = rand.Next(pos1);
            int posToCopy = rand.Next(genCode.Length - pos1 + pos2);

            for (int i = 0; i < pos1 - pos2; i++)
            {
                genCode[posToCopy + i] = genCode[pos2 + i];
            }
        }

        public void MutationScramble()
        {
            //Get sequence of genes, randomly rearange it and put back on the same place.
            Random rand = new Random();
            int pos1 = rand.Next(genCode.Length);
            while (pos1 == 0)
            {
                pos1 = rand.Next(genCode.Length);
            }
            int pos2 = rand.Next(pos1);

            for (int i = 0; i < pos1 - pos2; i++)
            {
                int temp = genCode[pos2 + i];
                int posSwap = rand.Next(pos1 - pos2);
                genCode[pos2 + i] = genCode[pos2 + posSwap];
                genCode[pos2 + posSwap] = temp;
            }
        }

        public void MutationInsertion()
        {
            //Get one gene and randomly put it back.
            Random rand = new Random();
            int pos = rand.Next(genCode.Length);
            int pom = genCode[pos];
            for (int i = pos; i < genCode.Length - 1; i++)
                genCode[i] = genCode[i + 1];
            pos = rand.Next(genCode.Length);
            for (int i = pos + 1; i < genCode.Length; i++)
                genCode[i] = genCode[i - 1];
            genCode[pos] = pom;
        }

        public void MutationInversion()
        {
            //Invert sequence of genes.
            Random rand = new Random();
            int pos1 = rand.Next(genCode.Length);
            while (pos1 == 0)
            {
                pos1 = rand.Next(genCode.Length);
            }
            int pos2 = rand.Next(pos1);

            for (int i = 0; i < (pos1 - pos2) / 2; i++)
            {
                int pom = genCode[pos2 + i];
                genCode[pos2 + i] = genCode[pos1 - i];
                genCode[pos1 - i] = pom;
            }
        }

        public void MutationDisplacedInversion()
        {
            //Combination of inversion and displacement.
            Random rand = new Random();
            int pos1 = rand.Next(genCode.Length);
            while (pos1 == 0)
            {
                pos1 = rand.Next(genCode.Length);
            }
            int pos2 = rand.Next(pos1);

            for (int i = 0; i < (pos1 - pos2) / 2; i++)
            {
                int pom = genCode[pos2 + i];
                genCode[pos2 + i] = genCode[pos1 - i];
                genCode[pos1 - i] = pom;
            }

            int posToCopy = rand.Next(genCode.Length - pos1 + pos2);
            for (int i = 0; i < pos1 - pos2; i++)
            {
                genCode[posToCopy + i] = genCode[pos2 + i];
            }
        }

        internal static int Compare(UnitInt x, UnitInt y)
        {
            double r = x.fitnessValue - y.fitnessValue;
            if (r > 0)
                return 1;
            else if (r < 0)
                return -1;
            else
                return 0;
        }
    }

}